home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 7
/
Amiga Format AFCD07 (Dec 1996, Issue 91).iso
/
serious
/
shareware
/
programming
/
aros
/
dos
/
loadseg_elf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-13
|
7KB
|
303 lines
/*
(C) 1995-96 AROS - The Amiga Replacement OS
$Id: loadseg_elf.c,v 1.7 1996/09/13 17:50:07 digulla Exp $
$Log: loadseg_elf.c,v $
Revision 1.7 1996/09/13 17:50:07 digulla
Use IPTR
Revision 1.6 1996/08/15 13:18:21 digulla
First attempt to allow debugging in shared code but the strings are not
loaded correctly yet
Revision 1.5 1996/08/13 13:52:48 digulla
Replaced <dos/dosextens.h> by "dos_intern.h" or added "dos_intern.h"
Replaced __AROS_LA by __AROS_LHA
Revision 1.4 1996/08/03 18:21:10 digulla
Added support for linked files !
Revision 1.3 1996/08/01 17:40:54 digulla
Added standard header for all files
Desc:
Lang:
*/
#include <exec/memory.h>
#include <clib/exec_protos.h>
#include <dos/dosasl.h>
#include <clib/dos_protos.h>
#include <clib/aros_protos.h>
#include "dos_intern.h"
extern struct DosLibrary * DOSBase;
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_NOBITS 8
#define SHT_REL 9
#define RELO_32 1
#define RELO_PC32 2
struct elfheader
{
UBYTE ident[16];
UWORD type;
UWORD machine;
ULONG version;
APTR entry;
ULONG phoff;
ULONG shoff;
ULONG flags;
UWORD ehsize;
UWORD phentsize;
UWORD phnum;
UWORD shentsize;
UWORD shnum;
UWORD shstrndx;
};
struct sheader
{
ULONG name;
ULONG type;
ULONG flags;
APTR addr;
ULONG offset;
ULONG size;
ULONG link;
ULONG info;
ULONG addralign;
ULONG entsize;
};
struct symbol
{
ULONG name;
ULONG value;
ULONG size;
UBYTE info;
UBYTE other;
WORD shindex;
};
struct relo
{
ULONG addr;
ULONG info;
};
struct hunk
{
ULONG size;
UBYTE *memory;
};
int read_block(BPTR file, ULONG offset, APTR buffer, ULONG size)
{
LONG subsize;
UBYTE *buf=(UBYTE *)buffer;
if(Seek(file,offset,OFFSET_BEGINNING)<0)
return 1;
while(size)
{
subsize=Read(file,buf,size);
if(subsize==0)
{
((struct Process *)FindTask(NULL))->pr_Result2=ERROR_BAD_HUNK;
return 1;
}
if(subsize<0)
return 1;
buf+=subsize;
size-=subsize;
}
return 0;
}
BPTR LoadSeg_ELF(BPTR file)
{
UBYTE *shtab=NULL;
UBYTE *strtab=NULL;
struct symbol *symtab=NULL;
struct hunk *hunks=NULL;
struct relo *reltab=NULL;
ULONG numsym, numrel, i;
WORD t, mint=0, maxt=0;
struct elfheader eh;
struct sheader *sh;
UBYTE *loaded;
struct symbol *symbol;
BPTR last=0;
#define ERROR(a) { *error=a; goto end; }
LONG *error=&((struct Process *)FindTask(NULL))->pr_Result2;
if(read_block(file,0,&eh,sizeof(eh)))
goto end;
if(eh.ident[0]!=0x7f||eh.ident[1]!='E'||eh.ident[2]!='L'||eh.ident[3]!='F')
ERROR(ERROR_NOT_EXECUTABLE);
if(eh.type!=1||eh.machine!=3)
ERROR(ERROR_OBJECT_WRONG_TYPE);
shtab=(UBYTE *)AllocVec(eh.shentsize*eh.shnum,MEMF_ANY);
if(shtab==NULL)
ERROR(ERROR_NO_FREE_STORE);
if(read_block(file,eh.shoff,shtab,eh.shentsize*eh.shnum))
goto end;
for(t=0;;t++)
{
if(t==eh.shnum)
ERROR(ERROR_OBJECT_WRONG_TYPE);
sh=(struct sheader *)(shtab+t*eh.shentsize);
if(sh->type==SHT_SYMTAB)
break;
}
symtab=(struct symbol *)AllocVec(sh->size,MEMF_ANY);
if(symtab==NULL)
ERROR(ERROR_NO_FREE_STORE);
if(read_block(file,sh->offset,symtab,sh->size))
goto end;
numsym=sh->size/sizeof(struct symbol);
mint=maxt=symtab[0].shindex;
for(i=1;i<numsym;i++)
{
if(symtab[i].shindex<mint)
mint=symtab[i].shindex;
if(symtab[i].shindex>maxt)
maxt=symtab[i].shindex;
}
hunks=(struct hunk *)AllocVec(sizeof(struct hunk)*((LONG)maxt-mint+1),MEMF_CLEAR);
if(hunks==NULL)
ERROR(ERROR_NO_FREE_STORE);
hunks-=mint;
for(t=0;t<eh.shnum;t++)
{
sh=(struct sheader *)(shtab+t*eh.shentsize);
if(sh->type==SHT_PROGBITS||sh->type==SHT_NOBITS)
hunks[t].size=sh->size;
}
#if 0 /* doesn't work :( */
if (eh.shstrndx)
{
sh = (struct sheader *)(shtab + eh.shstrndx*eh.shentsize);
kprintf ("StrTab-Section: name=%d type=%d flags=%d\n",
sh->name, sh->type,sh->flags);
strtab=AllocVec(sh->size,MEMF_ANY);
if(symtab==NULL)
ERROR(ERROR_NO_FREE_STORE);
kprintf ("Reading StrTab at %d (offset=%ld, size=%ld)\n", eh.shstrndx, sh->offset, sh->size);
if(read_block(file,sh->offset,strtab,sh->size))
goto end;
}
#endif
for(i=0;i<numsym;i++)
if(symtab[i].shindex<0)
{
symtab[i].value=hunks[symtab[i].shindex].size;
hunks[symtab[i].shindex].size+=symtab[i].size;
if (strtab && symtab[i].name)
kprintf ("sym %s: %ld\n", &strtab[symtab[i].name], symtab[i].value);
}
for(t=mint;t<=maxt;t++)
if(hunks[t].size)
{
hunks[t].memory=(UBYTE *)AllocVec(hunks[t].size+sizeof(BPTR),MEMF_CLEAR);
if(hunks[t].memory==NULL)
ERROR(ERROR_NO_FREE_STORE);
hunks[t].memory+=sizeof(BPTR);
}
loaded=NULL;
for(t=0;t<eh.shnum;t++)
{
sh=(struct sheader *)(shtab+t*eh.shentsize);
switch(sh->type)
{
case SHT_PROGBITS:
if(read_block(file,sh->offset,hunks[t].memory,sh->size))
goto end;
loaded=hunks[t].memory;
/* VPrintf ("Loaded PROGBITS at %08lx\n", (ULONG*)&loaded); */
break;
case SHT_REL:
if(loaded==NULL)
ERROR(ERROR_OBJECT_WRONG_TYPE);
reltab=AllocVec(sh->size,MEMF_ANY);
if(reltab==NULL)
ERROR(ERROR_NO_FREE_STORE);
if(read_block(file,sh->offset,reltab,sh->size))
goto end;
numrel=sh->size/sizeof(struct relo);
for(i=0;i<numrel;i++)
{
symbol=&symtab[reltab[i].info>>8];
switch(reltab[i].info&0xff)
{
case RELO_32:
*(ULONG *)&loaded[reltab[i].addr]+=
(IPTR)hunks[symbol->shindex].memory+symbol->value;
break;
case RELO_PC32:
*(ULONG *)&loaded[reltab[i].addr]+=
(IPTR)hunks[symbol->shindex].memory +
symbol->value - (IPTR)&loaded[reltab[i].addr];
break;
default:
ERROR(ERROR_BAD_HUNK);
}
}
FreeVec(reltab);
reltab=NULL;
loaded=NULL;
break;
}
}
for(t=mint;t<0;t++)
if(hunks[t].size)
{
((BPTR *)hunks[t].memory)[-1]=last;
last=MKBADDR((BPTR *)hunks[t].memory-1);
}
for(t=maxt;t>=0;t--)
if(hunks[t].size)
{
((BPTR *)hunks[t].memory)[-1]=last;
last=MKBADDR((BPTR *)hunks[t].memory-1);
}
FreeVec(hunks+mint);
hunks=NULL;
end:
FreeVec(reltab);
if(hunks!=NULL)
{
for(t=mint;t<=maxt;t++)
if(hunks[t].memory!=NULL)
FreeVec(hunks[t].memory-sizeof(BPTR));
FreeVec(hunks+mint);
}
if (strtab)
FreeVec (strtab);
FreeVec(symtab);
FreeVec(shtab);
return last;
}